﻿using Autofac;
using Autofac.Core;
using System;
using System.Reflection;

namespace ConsoleApp_AutoFac
{
    class Program
    {

        static IContainer _container;
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!_Autofac_Demo");

            InitContainer();

            WriteDate();

            var service = GetService<SimpleService>();
            Console.WriteLine(service.Add(1, 3));
            service.Close();

            RegisterLifeTest();

            InstanceDemoTest();

            GenericDemoAnalysis();

            Console.ReadKey();
        }

        private static void GenericDemoAnalysis()
        {
            Console.WriteLine("%%%%%%%%%%%%%%%%开始%%%%%%%%%%%%%%%%%%%");
            using var genScope = _container.BeginLifetimeScope();
            //var v = genScope.Resolve(typeof(GenericDemo<>));

            Console.WriteLine("%%%%%%%%%%%%%%%%结束%%%%%%%%%%%%%%%%%%%");
        }

        private static void InstanceDemoTest()
        {
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("################实例注入测试 开始#################");
            using (var scope = _container.BeginLifetimeScope())
            {
                var reB = scope.ResolveOptional<Bird>();
                //var b = scope.Resolve<Bird>();
                // b.HowToFaly();
            }
            Console.WriteLine("################实例注入测试 结束#################");
        }

        private static void RegisterLifeTest()
        {
            Console.WriteLine("****************生命周期 开始******************");
            using (var scope = _container.BeginLifetimeScope())
            {
                for (int i = 0; i < 3; i++)
                {
                    if (scope.TryResolve<People>(out People p))
                    {
                        p.Say();
                    }
                    else
                    {
                        Console.WriteLine("fail");
                    }
                }

                for (int i = 0; i < 3; i++)
                {
                    if (scope.TryResolve(out Dog p))
                    {
                        p.Say();
                    }
                    else
                    {
                        Console.WriteLine("fail");
                    }
                }

                for (int i = 0; i < 3; i++)
                {
                    if (scope.TryResolve(out Cat p))
                    {
                        p.Say();
                    }
                    else
                    {
                        Console.WriteLine("fail");
                    }
                }
            }

            for (int i = 0; i < 3; i++)
            {
                using var scope = _container.BeginLifetimeScope();
                if (scope.TryResolve(out Dog d))
                {
                    d.Say();
                }
                else
                {
                    Console.WriteLine("fail");
                }
            }

            for (int i = 0; i < 3; i++)
            {
                using var scope = _container.BeginLifetimeScope();
                if (scope.TryResolve<People>(out People p))
                {
                    p.Say();
                }
                else
                {
                    Console.WriteLine("fail");
                }
            }

            Console.WriteLine("****************生命周期 结束******************");


            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine();

            Console.WriteLine("————————————————带参数的获取实例对象  开始————————————————");
            /*
                NamedParameter - 通过名称匹配目标参数

                TypedParameter - 通过类型匹配目标参数 (需要匹配具体类型)

                ResolvedParameter - 灵活的参数匹配
             */
            using (var scoper = _container.BeginLifetimeScope())
            {
                var c = scoper.Resolve<Chicken>(new TypedParameter(typeof(int), 12), new TypedParameter(typeof(string), "龙哈天"));
                c.Say();

                //var labC = scoper.ResolveOptional<Chicken>();
                //labC?.Say();
            }
            Console.WriteLine("————————————————带参数的获取实例对象  结束————————————————");
        }

        private static void InitContainer()
        {

            //创建一个containerBuilder
            var facBuilder = new ContainerBuilder();


            #region  通过反射注册

            // 注册接口 通常使用的方式
            facBuilder.RegisterType(typeof(ConsoleOutPut)).As<IOutPut>();
            // facBuilder.RegisterType(typeof(TodayWrite)).As<IDateWrite>();
            //这种写法好像更加方便  自动以其实现的所有接口类型暴露（包括IDisposable接口）
            facBuilder.RegisterType(typeof(TodayWrite)).AsSelf().AsImplementedInterfaces();

            //注册服务通常使用方式
            facBuilder.RegisterType(typeof(SimpleService)).AsSelf().As<IServiceTest>().Named<IServiceTest>(typeof(SimpleService).FullName);

            #endregion

            #region 注册时候的生命周期
            //单例注册
            facBuilder.RegisterType(typeof(People)).SingleInstance();
            //同一个请求用同一个对象
            facBuilder.RegisterType(typeof(Dog)).InstancePerLifetimeScope();
            //一直都用新对象
            facBuilder.RegisterType(typeof(Cat));//.InstancePerDependency();

            //通过构造函数注入
            facBuilder.RegisterType(typeof(Chicken)).UsingConstructor(typeof(int), typeof(string));
            #endregion


            #region 通过实例注入

            Bird b = new Bird("龙浩天");
            facBuilder.RegisterInstance<IFlay>(b);

            //如果单例中存在实例且需要在容器中被组件使用时
            facBuilder.RegisterInstance(SingleFlay.GetSingleFlay).ExternallyOwned();

            #endregion


            //lambda 表达式注入
            facBuilder.Register(x => new Chicken(12, "lambda注入")).As<ISay>();

            //泛型注入
            facBuilder.RegisterGeneric(typeof(GenericDemo<>)).As(typeof(IGeneric<>)).InstancePerLifetimeScope();

            //条件注入
            //OnlyIf() - 提供一个表达式, 表示只有满足条件，才会执行语句。
            //IfNotRegistered() - 表示没有其他服务注册的情况下，就执行语句。
            facBuilder.Register(x => new Chicken(12, "lambda注入")).As<ISay>().OnlyIf(f => false);
            facBuilder.RegisterInstance(SingleFlay.GetSingleFlay).ExternallyOwned().IfNotRegistered(typeof(IFlay));

            //属性注入  属性的修饰符必须是 public
            //注册组件方法，并使用属性注入PropertiesAutowired()标注。

            #region 在.netcore 中如果注册不成功注意事项
                            /*在Startup.cs中修改ConfigureServices方法，替换从IServiceProvider中解析控制器实例的所有者。
                        public void ConfigureServices(IServiceCollection services)
                        {
                            //替换控制器的所有者
                            services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());

                            services.AddControllers();

                        }
                注意,替换的方法一定要在AddControllers之前。

                在ContainerBuilder中通过注册控制器，并使用属性注入功能实现.
                public void ConfigureContainer(ContainerBuilder builder)
                { 
                    //找到所有的controller进行注册，并使用属性注入功能
                    var controllerTypesInassembly = typeof(Startup).Assembly.GetExportedTypes()
                        .Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
                  builder.RegisterTypes(controllerTypesInassembly).PropertiesAutowired();
    
                    builder.RegisterType<TransientService>().As<ITransientService>().PropertiesAutowired();
                }
                这样就可以在Controller中进行属性注入了；*/
            #endregion

            facBuilder.RegisterType(typeof(Chicken)).AsImplementedInterfaces().PropertiesAutowired();

            //程序集注册
            var assemblies = Assembly.GetExecutingAssembly();

            facBuilder.RegisterAssemblyTypes(assemblies)//程序集内所有具象类 
            .Where(c => c.Name.EndsWith("Service"))
            .PublicOnly()//只要public访问权限的
            .Where(cc => cc.IsClass)//只要class型（主要为了排除值和interface类型） 
            .AsImplementedInterfaces();//自动以其实现的所有接口类型暴露（包括IDisposable接口）

            //            说明：
            //RegisterAssemblyTypes() ：接收包含一个或多个程序集的数组作为参数
            //RegisterAssemblyModules() : 接收模块作为参数，进行模块扫描注册
            //PublicOnly() ：指定公有方法被注册
            //Where() ：要过滤注册的类型
            //Except() ：要排除的类型
            //As() ：反射出其实现的接口
            //AsImplementedInterfaces() ： 自动以其实现的所有接口类型暴露（包括IDisposable接口）

            _container = facBuilder.Build();
        }

        public static void WriteDate()
        {
            if (_container == null)
            {
                return;
            }

            using (var scope = _container.BeginLifetimeScope())
            {
                scope.Resolve<IDateWrite>().WriteDate();
            }
        }

        /// <summary>
        /// 用完对象记得释放 调用接口方法 IServiceClose
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T GetService<T>() where T : class, IServiceClose
        {
            T ser = default;
            var scope = _container.BeginLifetimeScope();
            ser = _container.ResolveOptional<T>() as T;
            ser.Close = scope.Dispose;
            if (ser == null)
            {
                if (scope.TryResolve(out ser))
                {

                }
            }
            return ser;

        }
    }
}
